using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class Deformer : StateMachineBehaviour
{
    public List<deformData> timeline;

    public override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        float curtime = stateInfo.normalizedTime % 1 * stateInfo.length;
        Transform attachment;
        List<Vector3> pos_f = new List<Vector3>();
        List<Vector3> pos_n = new List<Vector3>();
        SkinnedMeshRenderer skinned;
        var isbake = animator.TryGetComponent<SkinnedMeshRenderer>(out skinned);
        Vector3[] pos_all = isbake ? skinned.sharedMesh.vertices : new Vector3[0];
        foreach (var item in timeline)
        {
            attachment = animator.transform.Find(item.attachment_path);
            if (attachment == null) continue;
            float relative_time = curtime;
            float curve_length = curtime;
            bool haskey = false;
            float curve_type = 0;
            int n = 0, m = item.deformTimeDatas.Count;
            for (; n < m && item.deformTimeDatas[n].time < curtime; n++)
            {
                haskey = true;
            }
            if (!haskey) continue;
            curve_type = item.deformTimeDatas[n - 1].curve_type;
            pos_f = item.deformTimeDatas[n - 1].pos;
            pos_n = n < m ? item.deformTimeDatas[n].pos : pos_f;
            curve_length = (n < m ? item.deformTimeDatas[n].time : stateInfo.length) - item.deformTimeDatas[n - 1].time;
            relative_time -= item.deformTimeDatas[n - 1].time;
            Vector3[] vertices = new Vector3[attachment.GetComponent<SkinnedMeshRenderer>().sharedMesh.vertices.Length];
            switch (curve_type)
            {
                case 1f:
                    vertices = pos_f.ToArray();
                    break;
                case 0f:
                default:
                    for (int i = 0, o = vertices.Length; i < o; i++)
                    {
                        vertices[i] = Vector3.Lerp(pos_f[i], pos_n[i], relative_time / curve_length);
                    }
                    break;
            }
            attachment.GetComponent<SkinnedMeshRenderer>().sharedMesh.vertices = vertices;
            if (isbake)
            {
                for (int i = item.start_idx; i <= item.end_idx; i++)
                {
                    pos_all[i] = vertices[i - item.start_idx];
                }
            }
        }
        if (isbake)
        {
            skinned.sharedMesh.vertices = pos_all.ToArray();
        }
    }
}
[Serializable]
public class deformData
{
    public string attachment_path;
    public List<deformTimeData> deformTimeDatas;
    public int start_idx;
    public int end_idx;
}
[Serializable]
public class deformTimeData
{
    public float time;
    public float curve_type;
    public List<Vector3> pos;
}